<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
<!-- openglwindow.qdoc -->
  <title>OpenGL Window Example | Qt GUI 5.14.2</title>
  <link rel="stylesheet" type="text/css" href="style/offline-simple.css" />
  <script type="text/javascript">
    document.getElementsByTagName("link").item(0).setAttribute("href", "style/offline.css");
    // loading style sheet breaks anchors that were jumped to before
    // so force jumping to anchor again
    setTimeout(function() {
        var anchor = location.hash;
        // need to jump to different anchor first (e.g. none)
        location.hash = "#";
        setTimeout(function() {
            location.hash = anchor;
        }, 0);
    }, 0);
  </script>
</head>
<body>
<div class="header" id="qtdocheader">
  <div class="main">
    <div class="main-rounded">
      <div class="navigationbar">
        <table><tr>
<td ><a href="../qtdoc/index.html">Qt 5.14</a></td><td ><a href="qtgui-index.html">Qt GUI</a></td><td >OpenGL Window Example</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right"><a href="qtgui-index.html">Qt 5.14.2 Reference Documentation</a></td>
        </tr></table>
      </div>
    </div>
<div class="content">
<div class="line">
<div class="content mainContent">
<div class="sidebar">
<div class="toc">
<h3><a name="toc">Contents</a></h3>
<ul>
<li class="level1"><a href="#openglwindow-super-class">OpenGLWindow Super Class</a></li>
<li class="level1"><a href="#example-opengl-rendering-sub-class">Example OpenGL Rendering Sub Class</a></li>
</ul>
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">OpenGL Window Example</h1>
<span class="subtitle"></span>
<!-- $$$openglwindow-brief -->
<p>This example shows how to create a minimal <a href="qwindow.html">QWindow</a> based application for the purpose of using OpenGL.</p>
<!-- @@@openglwindow -->
<!-- $$$openglwindow-description -->
<div class="descr"> <a name="details"></a>
<p class="centerAlign"><img src="images/openglwindow-example.png" alt="Screenshot of the OpenGLWindow example" /></p><p><b>Note: </b>This is a low level example of how to use <a href="qwindow.html">QWindow</a> with OpenGL. In practice you should consider using the higher level <a href="qopenglwindow.html">QOpenGLWindow</a> class.</p><a name="openglwindow-super-class"></a>
<h4 id="openglwindow-super-class">OpenGLWindow Super Class</h4>
<p>Our OpenGLWindow class acts as an API which is then subclassed to do the actual rendering. It has functions to make a request for render() to be called, either immediately with renderNow() or as soon as the event loop has finished processing the current batch of events with renderLater(). The OpenGLWindow subclass can either reimplement render() for OpenGL based rendering, or render(<a href="qpainter.html">QPainter</a> *) for rendering with a <a href="qpainter.html">QPainter</a>. Use OpenGLWindow::setAnimating(true) for render() to be called at the vertical refresh rate, assuming vertical sync is enabled in the underlying OpenGL drivers.</p>
<p>In the class that does the OpenGL rendering you will typically want to inherit from <a href="qopenglfunctions.html">QOpenGLFunctions</a>, as our OpenGLWindow does, in order to get platform independent access to OpenGL ES 2.0 functions. By inheriting from <a href="qopenglfunctions.html">QOpenGLFunctions</a> the OpenGL functions it contains will get precedence, and you will not have to worry about resolving those functions if you want your application to work with OpenGL as well as OpenGL ES 2.0&#x2e;</p>
<pre class="cpp">

  <span class="keyword">class</span> OpenGLWindow : <span class="keyword">public</span> <span class="type"><a href="qwindow.html">QWindow</a></span><span class="operator">,</span> <span class="keyword">protected</span> <span class="type"><a href="qopenglfunctions.html">QOpenGLFunctions</a></span>
  {
      Q_OBJECT
  <span class="keyword">public</span>:
      <span class="keyword">explicit</span> OpenGLWindow(<span class="type"><a href="qwindow.html">QWindow</a></span> <span class="operator">*</span>parent <span class="operator">=</span> <span class="number">0</span>);
      <span class="operator">~</span>OpenGLWindow();

      <span class="keyword">virtual</span> <span class="type">void</span> render(<span class="type"><a href="qpainter.html">QPainter</a></span> <span class="operator">*</span>painter);
      <span class="keyword">virtual</span> <span class="type">void</span> render();

      <span class="keyword">virtual</span> <span class="type">void</span> initialize();

      <span class="type">void</span> setAnimating(bool animating);

  <span class="keyword">public</span> <span class="keyword">slots</span>:
      <span class="type">void</span> renderLater();
      <span class="type">void</span> renderNow();

  <span class="keyword">protected</span>:
      bool event(<span class="type"><a href="../qtcore/qevent.html">QEvent</a></span> <span class="operator">*</span>event) override;

      <span class="type">void</span> exposeEvent(<span class="type"><a href="qexposeevent.html">QExposeEvent</a></span> <span class="operator">*</span>event) override;

  <span class="keyword">private</span>:
      bool m_animating;

      <span class="type"><a href="qopenglcontext.html">QOpenGLContext</a></span> <span class="operator">*</span>m_context;
      <span class="type"><a href="qopenglpaintdevice.html">QOpenGLPaintDevice</a></span> <span class="operator">*</span>m_device;
  };

</pre>
<p>The window's surface type must be set to <a href="qsurface.html#SurfaceType-enum">QSurface::OpenGLSurface</a> to indicate that the window is to be used for OpenGL rendering and not for rendering raster content with <a href="qpainter.html">QPainter</a> using a <a href="qbackingstore.html">QBackingStore</a>.</p>
<pre class="cpp">

  OpenGLWindow<span class="operator">::</span>OpenGLWindow(<span class="type"><a href="qwindow.html">QWindow</a></span> <span class="operator">*</span>parent)
      : <span class="type"><a href="qwindow.html">QWindow</a></span>(parent)
      <span class="operator">,</span> m_animating(<span class="keyword">false</span>)
      <span class="operator">,</span> m_context(<span class="number">0</span>)
      <span class="operator">,</span> m_device(<span class="number">0</span>)
  {
      setSurfaceType(<span class="type"><a href="qwindow.html">QWindow</a></span><span class="operator">::</span>OpenGLSurface);
  }

</pre>
<p>Any OpenGL initialization needed can be done by overriding the initialize() function, which is called once before the first call to render(), with a valid current <a href="qopenglcontext.html">QOpenGLContext</a>. As can be seen in the following code snippet, the default render(<a href="qpainter.html">QPainter</a> *) and initialize() implementations are empty, whereas the default render() implementation initializes a <a href="qopenglpaintdevice.html">QOpenGLPaintDevice</a> and then calls into render(<a href="qpainter.html">QPainter</a> *).</p>
<pre class="cpp">

  <span class="type">void</span> OpenGLWindow<span class="operator">::</span>render(<span class="type"><a href="qpainter.html">QPainter</a></span> <span class="operator">*</span>painter)
  {
      Q_UNUSED(painter);
  }

  <span class="type">void</span> OpenGLWindow<span class="operator">::</span>initialize()
  {
  }

  <span class="type">void</span> OpenGLWindow<span class="operator">::</span>render()
  {
      <span class="keyword">if</span> (<span class="operator">!</span>m_device)
          m_device <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qopenglpaintdevice.html">QOpenGLPaintDevice</a></span>;

      glClear(GL_COLOR_BUFFER_BIT <span class="operator">|</span> GL_DEPTH_BUFFER_BIT <span class="operator">|</span> GL_STENCIL_BUFFER_BIT);

      m_device<span class="operator">-</span><span class="operator">&gt;</span>setSize(size() <span class="operator">*</span> devicePixelRatio());
      m_device<span class="operator">-</span><span class="operator">&gt;</span>setDevicePixelRatio(devicePixelRatio());

      <span class="type"><a href="qpainter.html">QPainter</a></span> painter(m_device);
      render(<span class="operator">&amp;</span>painter);
  }

</pre>
<p>The renderLater() function simply calls <a href="qwindow.html#requestUpdate">QWindow::requestUpdate</a>() to schedule an update for when the system is ready to repaint.</p>
<p>We also call renderNow() when we get an expose event. The exposeEvent() is the notification to the window that its exposure, meaning visibility, on the screen has changed. When the expose event is received you can query <a href="qwindow.html#isExposed">QWindow::isExposed</a>() to find out whether or not the window is currently exposed. Do not render to or call <a href="qopenglcontext.html#swapBuffers">QOpenGLContext::swapBuffers</a>() on a window before it has received its first expose event, as before then its final size might be unknown, and in addition what is rendered might not even end up on the screen.</p>
<pre class="cpp">

  <span class="type">void</span> OpenGLWindow<span class="operator">::</span>renderLater()
  {
      requestUpdate();
  }

  bool OpenGLWindow<span class="operator">::</span>event(<span class="type"><a href="../qtcore/qevent.html">QEvent</a></span> <span class="operator">*</span>event)
  {
      <span class="keyword">switch</span> (event<span class="operator">-</span><span class="operator">&gt;</span>type()) {
      <span class="keyword">case</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>UpdateRequest:
          renderNow();
          <span class="keyword">return</span> <span class="keyword">true</span>;
      <span class="keyword">default</span>:
          <span class="keyword">return</span> <span class="type"><a href="qwindow.html">QWindow</a></span><span class="operator">::</span>event(event);
      }
  }

  <span class="type">void</span> OpenGLWindow<span class="operator">::</span>exposeEvent(<span class="type"><a href="qexposeevent.html">QExposeEvent</a></span> <span class="operator">*</span>event)
  {
      Q_UNUSED(event);

      <span class="keyword">if</span> (isExposed())
          renderNow();
  }

</pre>
<p>In renderNow() we return if we are not currently exposed, in which case rendering is delayed until we actually get an expose event. If we have not yet done so, we create the <a href="qopenglcontext.html">QOpenGLContext</a> with the same <a href="qsurfaceformat.html">QSurfaceFormat</a> as was set on the OpenGLWindow, and call initialize() for the sake of the sub class, and initializeOpenGLFunctions() in order for the <a href="qopenglfunctions.html">QOpenGLFunctions</a> super class to be associated with the correct <a href="qopenglcontext.html">QOpenGLContext</a>. In any case we make the context current by calling <a href="qopenglcontext.html#makeCurrent">QOpenGLContext::makeCurrent</a>(), call render() to do the actual rendering, and finally we schedule for the rendered contents to be made visible by calling <a href="qopenglcontext.html#swapBuffers">QOpenGLContext::swapBuffers</a>() with the OpenGLWindow as parameter.</p>
<p>Once the rendering of a frame using an OpenGL context is initiated by calling <a href="qopenglcontext.html#makeCurrent">QOpenGLContext::makeCurrent</a>(), giving the surface on which to render as a parameter, OpenGL commands can be issued. The commands can be issued either directly by including &lt;qopengl.h&gt;, which also includes the system's OpenGL headers, or as by using <a href="qopenglfunctions.html">QOpenGLFunctions</a>, which can either be inherited from for convenience, or accessed using <a href="qopenglcontext.html#functions">QOpenGLContext::functions</a>(). <a href="qopenglfunctions.html">QOpenGLFunctions</a> gives access to all the OpenGL ES 2.0 level OpenGL calls that are not already standard in both OpenGL ES 2.0 and desktop OpenGL. For more information about the OpenGL and OpenGL ES APIs, refer to the official <a href="http://www.opengl.org/registry/">OpenGL Registry</a> and <a href="http://www.khronos.org/registry/gles/">Khronos OpenGL ES API Registry</a>.</p>
<p>If animation has been enabled with OpenGLWindow::setAnimating(true), we call renderLater() to schedule another update request.</p>
<pre class="cpp">

  <span class="type">void</span> OpenGLWindow<span class="operator">::</span>renderNow()
  {
      <span class="keyword">if</span> (<span class="operator">!</span>isExposed())
          <span class="keyword">return</span>;

      bool needsInitialize <span class="operator">=</span> <span class="keyword">false</span>;

      <span class="keyword">if</span> (<span class="operator">!</span>m_context) {
          m_context <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qopenglcontext.html">QOpenGLContext</a></span>(<span class="keyword">this</span>);
          m_context<span class="operator">-</span><span class="operator">&gt;</span>setFormat(requestedFormat());
          m_context<span class="operator">-</span><span class="operator">&gt;</span>create();

          needsInitialize <span class="operator">=</span> <span class="keyword">true</span>;
      }

      m_context<span class="operator">-</span><span class="operator">&gt;</span>makeCurrent(<span class="keyword">this</span>);

      <span class="keyword">if</span> (needsInitialize) {
          initializeOpenGLFunctions();
          initialize();
      }

      render();

      m_context<span class="operator">-</span><span class="operator">&gt;</span>swapBuffers(<span class="keyword">this</span>);

      <span class="keyword">if</span> (m_animating)
          renderLater();
  }

</pre>
<p>Enabling animation also schedules an update request as shown in the following code snippet.</p>
<pre class="cpp">

  <span class="type">void</span> OpenGLWindow<span class="operator">::</span>setAnimating(bool animating)
  {
      m_animating <span class="operator">=</span> animating;

      <span class="keyword">if</span> (animating)
          renderLater();
  }

</pre>
<a name="example-opengl-rendering-sub-class"></a>
<h4 id="example-opengl-rendering-sub-class">Example OpenGL Rendering Sub Class</h4>
<p>Here we sub class OpenGLWindow to show how to do OpenGL to render a rotating triangle. By indirectly sub classing <a href="qopenglfunctions.html">QOpenGLFunctions</a> we gain access to all OpenGL ES 2.0 level functionality.</p>
<pre class="cpp">

  <span class="keyword">class</span> TriangleWindow : <span class="keyword">public</span> OpenGLWindow
  {
  <span class="keyword">public</span>:
      TriangleWindow();

      <span class="type">void</span> initialize() override;
      <span class="type">void</span> render() override;

  <span class="keyword">private</span>:
      GLuint m_posAttr;
      GLuint m_colAttr;
      GLuint m_matrixUniform;

      <span class="type"><a href="qopenglshaderprogram.html">QOpenGLShaderProgram</a></span> <span class="operator">*</span>m_program;
      <span class="type">int</span> m_frame;
  };

  TriangleWindow<span class="operator">::</span>TriangleWindow()
      : m_program(<span class="number">0</span>)
      <span class="operator">,</span> m_frame(<span class="number">0</span>)
  {
  }

</pre>
<p>In our main function we initialize <a href="qguiapplication.html">QGuiApplication</a> and instantiate our TriangleOpenGLWindow. We give it a <a href="qsurfaceformat.html">QSurfaceFormat</a> specifying that we want four samples of multisample antialiasing, as well as a default geometry. Since we want to have animation we call the above mentioned setAnimating() function with an argument of true.</p>
<pre class="cpp">

  <span class="type">int</span> main(<span class="type">int</span> argc<span class="operator">,</span> <span class="type">char</span> <span class="operator">*</span><span class="operator">*</span>argv)
  {
      <span class="type"><a href="qguiapplication.html">QGuiApplication</a></span> app(argc<span class="operator">,</span> argv);

      <span class="type"><a href="qsurfaceformat.html">QSurfaceFormat</a></span> format;
      format<span class="operator">.</span>setSamples(<span class="number">16</span>);

      TriangleWindow window;
      window<span class="operator">.</span>setFormat(format);
      window<span class="operator">.</span>resize(<span class="number">640</span><span class="operator">,</span> <span class="number">480</span>);
      window<span class="operator">.</span>show();

      window<span class="operator">.</span>setAnimating(<span class="keyword">true</span>);

      <span class="keyword">return</span> app<span class="operator">.</span>exec();
  }

</pre>
<p>The following code snippet shows the OpenGL shader program used in this example. The vertex and fragment shaders are relatively simple, doing vertex transformation and interpolated vertex coloring.</p>
<pre class="cpp">

  <span class="keyword">static</span> <span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>vertexShaderSource <span class="operator">=</span>
      <span class="string">&quot;attribute highp vec4 posAttr;\n&quot;</span>
      <span class="string">&quot;attribute lowp vec4 colAttr;\n&quot;</span>
      <span class="string">&quot;varying lowp vec4 col;\n&quot;</span>
      <span class="string">&quot;uniform highp mat4 matrix;\n&quot;</span>
      <span class="string">&quot;void main() {\n&quot;</span>
      <span class="string">&quot;   col = colAttr;\n&quot;</span>
      <span class="string">&quot;   gl_Position = matrix * posAttr;\n&quot;</span>
      <span class="string">&quot;}\n&quot;</span>;

  <span class="keyword">static</span> <span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>fragmentShaderSource <span class="operator">=</span>
      <span class="string">&quot;varying lowp vec4 col;\n&quot;</span>
      <span class="string">&quot;void main() {\n&quot;</span>
      <span class="string">&quot;   gl_FragColor = col;\n&quot;</span>
      <span class="string">&quot;}\n&quot;</span>;

</pre>
<p>Here is the code that loads the shaders and initializes the shader program By using <a href="qopenglshaderprogram.html">QOpenGLShaderProgram</a> instead of raw OpenGL we get the convenience that strips out the highp, mediump, and lowp qualifiers on desktop OpenGL, where they are not part of the standard. We store the attribute and uniform locations in member variables to avoid having to do the location lookup each frame.</p>
<pre class="cpp">

  <span class="type">void</span> TriangleWindow<span class="operator">::</span>initialize()
  {
      m_program <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qopenglshaderprogram.html">QOpenGLShaderProgram</a></span>(<span class="keyword">this</span>);
      m_program<span class="operator">-</span><span class="operator">&gt;</span>addShaderFromSourceCode(<span class="type"><a href="qopenglshader.html">QOpenGLShader</a></span><span class="operator">::</span>Vertex<span class="operator">,</span> vertexShaderSource);
      m_program<span class="operator">-</span><span class="operator">&gt;</span>addShaderFromSourceCode(<span class="type"><a href="qopenglshader.html">QOpenGLShader</a></span><span class="operator">::</span>Fragment<span class="operator">,</span> fragmentShaderSource);
      m_program<span class="operator">-</span><span class="operator">&gt;</span>link();
      m_posAttr <span class="operator">=</span> m_program<span class="operator">-</span><span class="operator">&gt;</span>attributeLocation(<span class="string">&quot;posAttr&quot;</span>);
      m_colAttr <span class="operator">=</span> m_program<span class="operator">-</span><span class="operator">&gt;</span>attributeLocation(<span class="string">&quot;colAttr&quot;</span>);
      m_matrixUniform <span class="operator">=</span> m_program<span class="operator">-</span><span class="operator">&gt;</span>uniformLocation(<span class="string">&quot;matrix&quot;</span>);
  }

</pre>
<p>Finally, here is our render() function, where we use OpenGL to set up the viewport, clear the background, and render a rotating triangle.</p>
<pre class="cpp">

  <span class="type">void</span> TriangleWindow<span class="operator">::</span>render()
  {
      <span class="keyword">const</span> <span class="type"><a href="../qtcore/qtglobal.html#qreal-typedef">qreal</a></span> retinaScale <span class="operator">=</span> devicePixelRatio();
      glViewport(<span class="number">0</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> width() <span class="operator">*</span> retinaScale<span class="operator">,</span> height() <span class="operator">*</span> retinaScale);

      glClear(GL_COLOR_BUFFER_BIT);

      m_program<span class="operator">-</span><span class="operator">&gt;</span>bind();

      QMatrix4x4 matrix;
      matrix<span class="operator">.</span>perspective(<span class="number">60.0f</span><span class="operator">,</span> <span class="number">4.0f</span><span class="operator">/</span><span class="number">3.0f</span><span class="operator">,</span> <span class="number">0.1f</span><span class="operator">,</span> <span class="number">100.0f</span>);
      matrix<span class="operator">.</span>translate(<span class="number">0</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> <span class="operator">-</span><span class="number">2</span>);
      matrix<span class="operator">.</span>rotate(<span class="number">100.0f</span> <span class="operator">*</span> m_frame <span class="operator">/</span> screen()<span class="operator">-</span><span class="operator">&gt;</span>refreshRate()<span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> <span class="number">1</span><span class="operator">,</span> <span class="number">0</span>);

      m_program<span class="operator">-</span><span class="operator">&gt;</span>setUniformValue(m_matrixUniform<span class="operator">,</span> matrix);

      GLfloat vertices<span class="operator">[</span><span class="operator">]</span> <span class="operator">=</span> {
          <span class="number">0.0f</span><span class="operator">,</span> <span class="number">0.707f</span><span class="operator">,</span>
          <span class="operator">-</span><span class="number">0.5f</span><span class="operator">,</span> <span class="operator">-</span><span class="number">0.5f</span><span class="operator">,</span>
          <span class="number">0.5f</span><span class="operator">,</span> <span class="operator">-</span><span class="number">0.5f</span>
      };

      GLfloat colors<span class="operator">[</span><span class="operator">]</span> <span class="operator">=</span> {
          <span class="number">1.0f</span><span class="operator">,</span> <span class="number">0.0f</span><span class="operator">,</span> <span class="number">0.0f</span><span class="operator">,</span>
          <span class="number">0.0f</span><span class="operator">,</span> <span class="number">1.0f</span><span class="operator">,</span> <span class="number">0.0f</span><span class="operator">,</span>
          <span class="number">0.0f</span><span class="operator">,</span> <span class="number">0.0f</span><span class="operator">,</span> <span class="number">1.0f</span>
      };

      glVertexAttribPointer(m_posAttr<span class="operator">,</span> <span class="number">2</span><span class="operator">,</span> GL_FLOAT<span class="operator">,</span> GL_FALSE<span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> vertices);
      glVertexAttribPointer(m_colAttr<span class="operator">,</span> <span class="number">3</span><span class="operator">,</span> GL_FLOAT<span class="operator">,</span> GL_FALSE<span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> colors);

      glEnableVertexAttribArray(<span class="number">0</span>);
      glEnableVertexAttribArray(<span class="number">1</span>);

      glDrawArrays(GL_TRIANGLES<span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> <span class="number">3</span>);

      glDisableVertexAttribArray(<span class="number">1</span>);
      glDisableVertexAttribArray(<span class="number">0</span>);

      m_program<span class="operator">-</span><span class="operator">&gt;</span>release();

      <span class="operator">+</span><span class="operator">+</span>m_frame;
  }

</pre>
<p><a href="https://code.qt.io/cgit/qt/qtbase.git/tree/examples/gui/openglwindow?h=5.14">Example project @ code.qt.io</a></p>
</div>
<!-- @@@openglwindow -->
        </div>
       </div>
   </div>
   </div>
</div>
<div class="footer">
   <p>
   <acronym title="Copyright">&copy;</acronym> 2020 The Qt Company Ltd.
   Documentation contributions included herein are the copyrights of
   their respective owners.<br/>    The documentation provided herein is licensed under the terms of the    <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation    License version 1.3</a> as published by the Free Software Foundation.<br/>    Qt and respective logos are trademarks of The Qt Company Ltd.     in Finland and/or other countries worldwide. All other trademarks are property
   of their respective owners. </p>
</div>
</body>
</html>
